/**
 * @file ec_curves.c
 * @brief Elliptic curves
 *
 * @section License
 *
 * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneCrypto Open.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 1.8.6
 **/

//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL

//Dependencies
#include "core/crypto.h"
#include "ecc/ec_curves.h"
#include "encoding/oid.h"
#include "debug.h"

//Check crypto library configuration
#if (EC_SUPPORT == ENABLED)

//Macro definition
#define CLEAR_WORD32(a, i, n) cryptoMemset((a)->data + i, 0, n * MPI_INT_SIZE);
#define COPY_WORD32(a, i, b, j, n) cryptoMemcpy((a)->data + i, (b)->data + j, n * MPI_INT_SIZE);

//secp112r1 OID (1.3.132.0.6)
const uint8_t SECP112R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x06};
//secp112r2 OID (1.3.132.0.7)
const uint8_t SECP112R2_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x07};
//secp128r1 OID (1.3.132.0.28)
const uint8_t SECP128R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1C};
//secp128r2 OID (1.3.132.0.29)
const uint8_t SECP128R2_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1D};
//secp160k1 OID (1.3.132.0.9)
const uint8_t SECP160K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x09};
//secp160r1 OID (1.3.132.0.8)
const uint8_t SECP160R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x08};
//secp160r2 OID (1.3.132.0.30)
const uint8_t SECP160R2_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1E};
//secp192k1 OID (1.3.132.0.31)
const uint8_t SECP192K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1F};
//secp192r1 OID (1.2.840.10045.3.1.1)
const uint8_t SECP192R1_OID[8] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01};
//secp224k1 OID (1.3.132.0.32)
const uint8_t SECP224K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x20};
//secp224r1 OID (1.3.132.0.33)
const uint8_t SECP224R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x21};
//secp256k1 OID (1.3.132.0.10)
const uint8_t SECP256K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x0A};
//secp256r1 OID (1.2.840.10045.3.1.7)
const uint8_t SECP256R1_OID[8] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07};
//secp384r1 OID (1.3.132.0.34)
const uint8_t SECP384R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x22};
//secp521r1 OID (1.3.132.0.35)
const uint8_t SECP521R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x23};
//brainpoolP160r1 OID (1.3.36.3.3.2.8.1.1.1)
const uint8_t BRAINPOOLP160R1_OID[9] = {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01};
//brainpoolP192r1 OID (1.3.36.3.3.2.8.1.1.3)
const uint8_t BRAINPOOLP192R1_OID[9] = {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x03};
//brainpoolP224r1 OID (1.3.36.3.3.2.8.1.1.5)
const uint8_t BRAINPOOLP224R1_OID[9] = {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x05};
//brainpoolP256r1 OID (1.3.36.3.3.2.8.1.1.7)
const uint8_t BRAINPOOLP256R1_OID[9] = {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07};
//brainpoolP320r1 OID (1.3.36.3.3.2.8.1.1.9)
const uint8_t BRAINPOOLP320R1_OID[9] = {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x09};
//brainpoolP384r1 OID (1.3.36.3.3.2.8.1.1.11)
const uint8_t BRAINPOOLP384R1_OID[9] = {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B};
//brainpoolP512r1 OID (1.3.36.3.3.2.8.1.1.13)
const uint8_t BRAINPOOLP512R1_OID[9] = {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D};
//X25519 OID (1.3.101.110)
const uint8_t X25519_OID[3] = {0x2B, 0x65, 0x6E};
//X448 OID (1.3.101.111)
const uint8_t X448_OID[3] = {0x2B, 0x65, 0x6F};
//Ed25519 OID (1.3.101.112)
const uint8_t ED25519_OID[3] = {0x2B, 0x65, 0x70};
//Ed448 OID (1.3.101.113)
const uint8_t ED448_OID[3] = {0x2B, 0x65, 0x71};


#if (SECP112R1_SUPPORT == ENABLED)

/**
 * @brief secp112r1 elliptic curve
 **/

const EcCurveInfo secp112r1Curve =
{
   //Curve name
   "secp112r1",
   //Object identifier
   SECP112R1_OID,
   sizeof(SECP112R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x66, 0x80, 0x76, 0xBE, 0xAD, 0x20, 0x8B},
   14,
   //Curve parameter a
   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x66, 0x80, 0x76, 0xBE, 0xAD, 0x20, 0x88},
   14,
   //Curve parameter b
   {0x65, 0x9E, 0xF8, 0xBA, 0x04, 0x39, 0x16, 0xEE, 0xDE, 0x89, 0x11, 0x70, 0x2B, 0x22},
   14,
   //x-coordinate of the base point G
   {0x09, 0x48, 0x72, 0x39, 0x99, 0x5A, 0x5E, 0xE7, 0x6B, 0x55, 0xF9, 0xC2, 0xF0, 0x98},
   14,
   //y-coordinate of the base point G
   {0xA8, 0x9C, 0xE5, 0xAF, 0x87, 0x24, 0xC0, 0xA2, 0x3E, 0x0E, 0x0F, 0xF7, 0x75, 0x00},
   14,
   //Base point order q
   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x76, 0x28, 0xDF, 0xAC, 0x65, 0x61, 0xC5},
   14,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (SECP112R2_SUPPORT == ENABLED)

/**
 * @brief secp112r2 elliptic curve
 **/

const EcCurveInfo secp112r2Curve =
{
   //Curve name
   "secp112r2",
   //Object identifier
   SECP112R2_OID,
   sizeof(SECP112R2_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R2,
   //Prime modulus p
   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x66, 0x80, 0x76, 0xBE, 0xAD, 0x20, 0x8B},
   14,
   //Curve parameter a
   {0x61, 0x27, 0xC2, 0x4C, 0x05, 0xF3, 0x8A, 0x0A, 0xAA, 0xF6, 0x5C, 0x0E, 0xF0, 0x2C},
   14,
   //Curve parameter b
   {0x51, 0xDE, 0xF1, 0x81, 0x5D, 0xB5, 0xED, 0x74, 0xFC, 0xC3, 0x4C, 0x85, 0xD7, 0x09},
   14,
   //x-coordinate of the base point G
   {0x4B, 0xA3, 0x0A, 0xB5, 0xE8, 0x92, 0xB4, 0xE1, 0x64, 0x9D, 0xD0, 0x92, 0x86, 0x43},
   14,
   //y-coordinate of the base point G
   {0xAD, 0xCD, 0x46, 0xF5, 0x88, 0x2E, 0x37, 0x47, 0xDE, 0xF3, 0x6E, 0x95, 0x6E, 0x97},
   14,
   //Base point order q
   {0x36, 0xDF, 0x0A, 0xAF, 0xD8, 0xB8, 0xD7, 0x59, 0x7C, 0xA1, 0x05, 0x20, 0xD0, 0x4B},
   14,
   //Cofactor
   4,
   //Fast modular reduction
   NULL
};

#endif
#if (SECP128R1_SUPPORT == ENABLED)

/**
 * @brief secp128r1 elliptic curve
 **/

const EcCurveInfo secp128r1Curve =
{
   //Curve name
   "secp128r1",
   //Object identifier
   SECP128R1_OID,
   sizeof(SECP128R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
   16,
   //Curve parameter a
   {0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC},
   16,
   //Curve parameter b
   {0xE8, 0x75, 0x79, 0xC1, 0x10, 0x79, 0xF4, 0x3D, 0xD8, 0x24, 0x99, 0x3C, 0x2C, 0xEE, 0x5E, 0xD3},
   16,
   //x-coordinate of the base point G
   {0x16, 0x1F, 0xF7, 0x52, 0x8B, 0x89, 0x9B, 0x2D, 0x0C, 0x28, 0x60, 0x7C, 0xA5, 0x2C, 0x5B, 0x86},
   16,
   //y-coordinate of the base point G
   {0xCF, 0x5A, 0xC8, 0x39, 0x5B, 0xAF, 0xEB, 0x13, 0xC0, 0x2D, 0xA2, 0x92, 0xDD, 0xED, 0x7A, 0x83},
   16,
   //Base point order q
   {0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x75, 0xA3, 0x0D, 0x1B, 0x90, 0x38, 0xA1, 0x15},
   16,
   //Cofactor
   1,
   //Fast modular reduction
   secp128r1Mod
};

#endif
#if (SECP128R2_SUPPORT == ENABLED)

/**
 * @brief secp128r2 elliptic curve
 **/

const EcCurveInfo secp128r2Curve =
{
   //Curve name
   "secp128r2",
   //Object identifier
   SECP128R2_OID,
   sizeof(SECP128R2_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R2,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
   16,
   //Curve parameter a
   {0xD6, 0x03, 0x19, 0x98, 0xD1, 0xB3, 0xBB, 0xFE, 0xBF, 0x59, 0xCC, 0x9B, 0xBF, 0xF9, 0xAE, 0xE1},
   16,
   //Curve parameter b
   {0x5E, 0xEE, 0xFC, 0xA3, 0x80, 0xD0, 0x29, 0x19, 0xDC, 0x2C, 0x65, 0x58, 0xBB, 0x6D, 0x8A, 0x5D},
   16,
   //x-coordinate of the base point G
   {0x7B, 0x6A, 0xA5, 0xD8, 0x5E, 0x57, 0x29, 0x83, 0xE6, 0xFB, 0x32, 0xA7, 0xCD, 0xEB, 0xC1, 0x40},
   16,
   //y-coordinate of the base point G
   {0x27, 0xB6, 0x91, 0x6A, 0x89, 0x4D, 0x3A, 0xEE, 0x71, 0x06, 0xFE, 0x80, 0x5F, 0xC3, 0x4B, 0x44},
   16,
   //Base point order q
   {0x3F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x24, 0x72, 0x06, 0x13, 0xB5, 0xA3},
   16,
   //Cofactor
   4,
   //Fast modular reduction
   secp128r2Mod
};

#endif
#if (SECP160K1_SUPPORT == ENABLED)

/**
 * @brief secp160k1 elliptic curve
 **/

const EcCurveInfo secp160k1Curve =
{
   //Curve name
   "secp160k1",
   //Object identifier
   SECP160K1_OID,
   sizeof(SECP160K1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_K1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xAC, 0x73},
   20,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00},
   20,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x07},
   20,
   //x-coordinate of the base point G
   {0x3B, 0x4C, 0x38, 0x2C, 0xE3, 0x7A, 0xA1, 0x92, 0xA4, 0x01, 0x9E, 0x76, 0x30, 0x36, 0xF4, 0xF5,
    0xDD, 0x4D, 0x7E, 0xBB},
   20,
   //y-coordinate of the base point G
   {0x93, 0x8C, 0xF9, 0x35, 0x31, 0x8F, 0xDC, 0xED, 0x6B, 0xC2, 0x82, 0x86, 0x53, 0x17, 0x33, 0xC3,
    0xF0, 0x3C, 0x4F, 0xEE},
   20,
   //Base point order q
   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB8, 0xFA, 0x16, 0xDF, 0xAB,
    0x9A, 0xCA, 0x16, 0xB6, 0xB3},
   21,
   //Cofactor
   1,
   //Fast modular reduction
   secp160k1Mod
};

#endif
#if (SECP160R1_SUPPORT == ENABLED)

/**
 * @brief secp160r1 elliptic curve
 **/

const EcCurveInfo secp160r1Curve =
{
   //Curve name
   "secp160r1",
   //Object identifier
   SECP160R1_OID,
   sizeof(SECP160R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0x7F, 0xFF, 0xFF, 0xFF},
   20,
   //Curve parameter a
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0x7F, 0xFF, 0xFF, 0xFC},
   20,
   //Curve parameter b
   {0x1C, 0x97, 0xBE, 0xFC, 0x54, 0xBD, 0x7A, 0x8B, 0x65, 0xAC, 0xF8, 0x9F, 0x81, 0xD4, 0xD4, 0xAD,
    0xC5, 0x65, 0xFA, 0x45},
   20,
   //x-coordinate of the base point G
   {0x4A, 0x96, 0xB5, 0x68, 0x8E, 0xF5, 0x73, 0x28, 0x46, 0x64, 0x69, 0x89, 0x68, 0xC3, 0x8B, 0xB9,
    0x13, 0xCB, 0xFC, 0x82},
   20,
   //y-coordinate of the base point G
   {0x23, 0xA6, 0x28, 0x55, 0x31, 0x68, 0x94, 0x7D, 0x59, 0xDC, 0xC9, 0x12, 0x04, 0x23, 0x51, 0x37,
    0x7A, 0xC5, 0xFB, 0x32},
   20,
   //Base point order q
   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF4, 0xC8, 0xF9, 0x27, 0xAE,
    0xD3, 0xCA, 0x75, 0x22, 0x57},
   21,
   //Cofactor
   1,
   //Fast modular reduction
   secp160r1Mod
};

#endif
#if (SECP160R2_SUPPORT == ENABLED)

/**
 * @brief secp160r2 elliptic curve
 **/

const EcCurveInfo secp160r2Curve =
{
   //Curve name
   "secp160r2",
   //Object identifier
   SECP160R2_OID,
   sizeof(SECP160R2_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R2,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xAC, 0x73},
   20,
   //Curve parameter a
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xAC, 0x70},
   20,
   //Curve parameter b
   {0xB4, 0xE1, 0x34, 0xD3, 0xFB, 0x59, 0xEB, 0x8B, 0xAB, 0x57, 0x27, 0x49, 0x04, 0x66, 0x4D, 0x5A,
    0xF5, 0x03, 0x88, 0xBA},
   20,
   //x-coordinate of the base point G
   {0x52, 0xDC, 0xB0, 0x34, 0x29, 0x3A, 0x11, 0x7E, 0x1F, 0x4F, 0xF1, 0x1B, 0x30, 0xF7, 0x19, 0x9D,
    0x31, 0x44, 0xCE, 0x6D},
   20,
   //y-coordinate of the base point G
   {0xFE, 0xAF, 0xFE, 0xF2, 0xE3, 0x31, 0xF2, 0x96, 0xE0, 0x71, 0xFA, 0x0D, 0xF9, 0x98, 0x2C, 0xFE,
    0xA7, 0xD4, 0x3F, 0x2E},
   20,
   //Base point order q
   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1E, 0xE7, 0x86, 0xA8,
    0x18, 0xF3, 0xA1, 0xA1, 0x6B},
   21,
   //Cofactor
   1,
   //Fast modular reduction
   secp160r2Mod
};

#endif
#if (SECP192K1_SUPPORT == ENABLED)

/**
 * @brief secp192k1 elliptic curve
 **/

const EcCurveInfo secp192k1Curve =
{
   //Curve name
   "secp192k1",
   //Object identifier
   SECP192K1_OID,
   sizeof(SECP192K1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_K1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xEE, 0x37},
   24,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   24,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03},
   24,
   //x-coordinate of the base point G
   {0xDB, 0x4F, 0xF1, 0x0E, 0xC0, 0x57, 0xE9, 0xAE, 0x26, 0xB0, 0x7D, 0x02, 0x80, 0xB7, 0xF4, 0x34,
    0x1D, 0xA5, 0xD1, 0xB1, 0xEA, 0xE0, 0x6C, 0x7D},
   24,
   //y-coordinate of the base point G
   {0x9B, 0x2F, 0x2F, 0x6D, 0x9C, 0x56, 0x28, 0xA7, 0x84, 0x41, 0x63, 0xD0, 0x15, 0xBE, 0x86, 0x34,
    0x40, 0x82, 0xAA, 0x88, 0xD9, 0x5E, 0x2F, 0x9D},
   24,
   //Base point order q
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x26, 0xF2, 0xFC, 0x17,
    0x0F, 0x69, 0x46, 0x6A, 0x74, 0xDE, 0xFD, 0x8D},
   24,
   //Cofactor
   1,
   //Fast modular reduction
   secp192k1Mod
};

#endif
#if (SECP192R1_SUPPORT == ENABLED)

/**
 * @brief secp192r1 elliptic curve
 **/

const EcCurveInfo secp192r1Curve =
{
   //Curve name
   "secp192r1",
   //Object identifier
   SECP192R1_OID,
   sizeof(SECP192R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
   24,
   //Curve parameter a
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC},
   24,
   //Curve parameter b
   {0x64, 0x21, 0x05, 0x19, 0xE5, 0x9C, 0x80, 0xE7, 0x0F, 0xA7, 0xE9, 0xAB, 0x72, 0x24, 0x30, 0x49,
    0xFE, 0xB8, 0xDE, 0xEC, 0xC1, 0x46, 0xB9, 0xB1},
   24,
   //x-coordinate of the base point G
   {0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6, 0x7C, 0xBF, 0x20, 0xEB, 0x43, 0xA1, 0x88, 0x00,
    0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12},
   24,
   //y-coordinate of the base point G
   {0x07, 0x19, 0x2B, 0x95, 0xFF, 0xC8, 0xDA, 0x78, 0x63, 0x10, 0x11, 0xED, 0x6B, 0x24, 0xCD, 0xD5,
    0x73, 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11},
   24,
   //Base point order q
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0xDE, 0xF8, 0x36,
    0x14, 0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31},
   24,
   //Cofactor
   1,
   //Fast modular reduction
   secp192r1Mod
};

#endif
#if (SECP224K1_SUPPORT == ENABLED)

/**
 * @brief secp224k1 elliptic curve
 **/

const EcCurveInfo secp224k1Curve =
{
   //Curve name
   "secp224k1",
   //Object identifier
   SECP224K1_OID,
   sizeof(SECP224K1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_K1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xE5, 0x6D},
   28,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   28,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05},
   28,
   //x-coordinate of the base point G
   {0xA1, 0x45, 0x5B, 0x33, 0x4D, 0xF0, 0x99, 0xDF, 0x30, 0xFC, 0x28, 0xA1, 0x69, 0xA4, 0x67, 0xE9,
    0xE4, 0x70, 0x75, 0xA9, 0x0F, 0x7E, 0x65, 0x0E, 0xB6, 0xB7, 0xA4, 0x5C},
   28,
   //y-coordinate of the base point G
   {0x7E, 0x08, 0x9F, 0xED, 0x7F, 0xBA, 0x34, 0x42, 0x82, 0xCA, 0xFB, 0xD6, 0xF7, 0xE3, 0x19, 0xF7,
    0xC0, 0xB0, 0xBD, 0x59, 0xE2, 0xCA, 0x4B, 0xDB, 0x55, 0x6D, 0x61, 0xA5},
   28,
   //Base point order q
   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xDC,
    0xE8, 0xD2, 0xEC, 0x61, 0x84, 0xCA, 0xF0, 0xA9, 0x71, 0x76, 0x9F, 0xB1, 0xF7},
   29,
   //Cofactor
   1,
   //Fast modular reduction
   secp224k1Mod
};

#endif
#if (SECP224R1_SUPPORT == ENABLED)

/**
 * @brief secp224r1 elliptic curve
 **/

const EcCurveInfo secp224r1Curve =
{
   //Curve name
   "secp224r1",
   //Object identifier
   SECP224R1_OID,
   sizeof(SECP224R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
   28,
   //Curve parameter a
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE},
   28,
   //Curve parameter b
   {0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xB0, 0xB7,
    0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43, 0x23, 0x55, 0xFF, 0xB4},
   28,
   //x-coordinate of the base point G
   {0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, 0x90, 0xB9, 0x4A, 0x03, 0xC1, 0xD3,
    0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6, 0x11, 0x5C, 0x1D, 0x21},
   28,
   //y-coordinate of the base point G
   {0xBD, 0x37, 0x63, 0x88, 0xB5, 0xF7, 0x23, 0xFB, 0x4C, 0x22, 0xDF, 0xE6, 0xCD, 0x43, 0x75, 0xA0,
    0x5A, 0x07, 0x47, 0x64, 0x44, 0xD5, 0x81, 0x99, 0x85, 0x00, 0x7E, 0x34},
   28,
   //Base point order q
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x16, 0xA2,
    0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45, 0x5C, 0x5C, 0x2A, 0x3D},
   28,
   //Cofactor
   1,
   //Fast modular reduction
   secp224r1Mod
};

#endif
#if (SECP256K1_SUPPORT == ENABLED)

/**
 * @brief secp256k1 elliptic curve
 **/

const EcCurveInfo secp256k1Curve =
{
   //Curve name
   "secp256k1",
   //Object identifier
   SECP256K1_OID,
   sizeof(SECP256K1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_K1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F},
   32,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   32,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07},
   32,
   //x-coordinate of the base point G
   {0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
    0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98},
   32,
   //y-coordinate of the base point G
   {0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8,
    0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8},
   32,
   //Base point order q
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41},
   32,
   //Cofactor
   1,
   //Fast modular reduction
   secp256k1Mod
};

#endif
#if (SECP256R1_SUPPORT == ENABLED)

/**
 * @brief secp256r1 elliptic curve
 **/

const EcCurveInfo secp256r1Curve =
{
   //Curve name
   "secp256r1",
   //Object identifier
   SECP256R1_OID,
   sizeof(SECP256R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
   32,
   //Curve parameter a
   {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC},
   32,
   //Curve parameter b
   {0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC,
    0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B},
   32,
   //x-coordinate of the base point G
   {0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
    0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96},
   32,
   //y-coordinate of the base point G
   {0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
    0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5},
   32,
   //Base point order q
   {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51},
   32,
   //Cofactor
   1,
   //Fast modular reduction
   secp256r1Mod
};

#endif
#if (SECP384R1_SUPPORT == ENABLED)

/**
 * @brief secp384r1 elliptic curve
 **/

const EcCurveInfo secp384r1Curve =
{
   //Curve name
   "secp384r1",
   //Object identifier
   SECP384R1_OID,
   sizeof(SECP384R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF},
   48,
   //Curve parameter a
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC},
   48,
   //Curve parameter b
   {0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, 0xE3, 0xF8, 0x2D, 0x19,
    0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A,
    0xC6, 0x56, 0x39, 0x8D, 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF},
   48,
   //x-coordinate of the base point G
   {0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, 0x74,
    0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38,
    0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7},
   48,
   //y-coordinate of the base point G
   {0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, 0x29,
    0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0,
    0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F},
   48,
   //Base point order q
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
    0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73},
   48,
   //Cofactor
   1,
   //Fast modular reduction
   secp384r1Mod
};

#endif
#if (SECP521R1_SUPPORT == ENABLED)

/**
 * @brief secp521r1 elliptic curve
 **/

const EcCurveInfo secp521r1Curve =
{
   //Curve name
   "secp521r1",
   //Object identifier
   SECP521R1_OID,
   sizeof(SECP521R1_OID),
   //Curve type
   EC_CURVE_TYPE_SECP_R1,
   //Prime modulus p
   {0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF},
   66,
   //Curve parameter a
   {0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFC},
   66,
   //Curve parameter b
   {0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A, 0x21, 0xA0, 0xB6, 0x85,
    0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1,
    0x09, 0xE1, 0x56, 0x19, 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1,
    0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45, 0x1F, 0xD4, 0x6B, 0x50,
    0x3F, 0x00},
   66,
   //x-coordinate of the base point G
   {0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23, 0x95,
    0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D,
    0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF,
    0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2, 0xE5,
    0xBD, 0x66},
   66,
   //y-coordinate of the base point G
   {0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F, 0xB4, 0x2C, 0x7D,
    0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E,
    0x66, 0x2C, 0x97, 0xEE, 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD,
    0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94, 0x76, 0x9F, 0xD1,
    0x66, 0x50},
   66,
   //Base point order q
   {0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
    0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
    0x64, 0x09},
   66,
   //Cofactor
   1,
   //Fast modular reduction
   secp521r1Mod
};

#endif
#if (BRAINPOOLP160R1_SUPPORT == ENABLED)

/**
 * @brief brainpoolP160r1 elliptic curve
 **/

const EcCurveInfo brainpoolP160r1Curve =
{
   //Curve name
   "brainpoolP160r1",
   //Object identifier
   BRAINPOOLP160R1_OID,
   sizeof(BRAINPOOLP160R1_OID),
   //Curve type
   EC_CURVE_TYPE_BRAINPOOLP_R1,
   //Prime modulus p
   {0xE9, 0x5E, 0x4A, 0x5F, 0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0xC7, 0xAD, 0x95, 0xB3, 0xD8, 0x13,
    0x95, 0x15, 0x62, 0x0F},
   20,
   //Curve parameter a
   {0x34, 0x0E, 0x7B, 0xE2, 0xA2, 0x80, 0xEB, 0x74, 0xE2, 0xBE, 0x61, 0xBA, 0xDA, 0x74, 0x5D, 0x97,
    0xE8, 0xF7, 0xC3, 0x00},
   20,
   //Curve parameter b
   {0x1E, 0x58, 0x9A, 0x85, 0x95, 0x42, 0x34, 0x12, 0x13, 0x4F, 0xAA, 0x2D, 0xBD, 0xEC, 0x95, 0xC8,
    0xD8, 0x67, 0x5E, 0x58},
   20,
   //x-coordinate of the base point G
   {0xBE, 0xD5, 0xAF, 0x16, 0xEA, 0x3F, 0x6A, 0x4F, 0x62, 0x93, 0x8C, 0x46, 0x31, 0xEB, 0x5A, 0xF7,
    0xBD, 0xBC, 0xDB, 0xC3},
   20,
   //y-coordinate of the base point G
   {0x16, 0x67, 0xCB, 0x47, 0x7A, 0x1A, 0x8E, 0xC3, 0x38, 0xF9, 0x47, 0x41, 0x66, 0x9C, 0x97, 0x63,
    0x16, 0xDA, 0x63, 0x21},
   20,
   //Base point order q
   {0xE9, 0x5E, 0x4A, 0x5F, 0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0x59, 0x91, 0xD4, 0x50, 0x29, 0x40,
    0x9E, 0x60, 0xFC, 0x09},
   20,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (BRAINPOOLP192R1_SUPPORT == ENABLED)

/**
 * @brief brainpoolP192r1 elliptic curve
 **/

const EcCurveInfo brainpoolP192r1Curve =
{
   //Curve name
   "brainpoolP192r1",
   //Object identifier
   BRAINPOOLP192R1_OID,
   sizeof(BRAINPOOLP192R1_OID),
   //Curve type
   EC_CURVE_TYPE_BRAINPOOLP_R1,
   //Prime modulus p
   {0xC3, 0x02, 0xF4, 0x1D, 0x93, 0x2A, 0x36, 0xCD, 0xA7, 0xA3, 0x46, 0x30, 0x93, 0xD1, 0x8D, 0xB7,
    0x8F, 0xCE, 0x47, 0x6D, 0xE1, 0xA8, 0x62, 0x97},
   24,
   //Curve parameter a
   {0x6A, 0x91, 0x17, 0x40, 0x76, 0xB1, 0xE0, 0xE1, 0x9C, 0x39, 0xC0, 0x31, 0xFE, 0x86, 0x85, 0xC1,
    0xCA, 0xE0, 0x40, 0xE5, 0xC6, 0x9A, 0x28, 0xEF},
   24,
   //Curve parameter b
   {0x46, 0x9A, 0x28, 0xEF, 0x7C, 0x28, 0xCC, 0xA3, 0xDC, 0x72, 0x1D, 0x04, 0x4F, 0x44, 0x96, 0xBC,
    0xCA, 0x7E, 0xF4, 0x14, 0x6F, 0xBF, 0x25, 0xC9},
   24,
   //x-coordinate of the base point G
   {0xC0, 0xA0, 0x64, 0x7E, 0xAA, 0xB6, 0xA4, 0x87, 0x53, 0xB0, 0x33, 0xC5, 0x6C, 0xB0, 0xF0, 0x90,
    0x0A, 0x2F, 0x5C, 0x48, 0x53, 0x37, 0x5F, 0xD6},
   24,
   //y-coordinate of the base point G
   {0x14, 0xB6, 0x90, 0x86, 0x6A, 0xBD, 0x5B, 0xB8, 0x8B, 0x5F, 0x48, 0x28, 0xC1, 0x49, 0x00, 0x02,
    0xE6, 0x77, 0x3F, 0xA2, 0xFA, 0x29, 0x9B, 0x8F},
   24,
   //Base point order q
   {0xC3, 0x02, 0xF4, 0x1D, 0x93, 0x2A, 0x36, 0xCD, 0xA7, 0xA3, 0x46, 0x2F, 0x9E, 0x9E, 0x91, 0x6B,
    0x5B, 0xE8, 0xF1, 0x02, 0x9A, 0xC4, 0xAC, 0xC1},
   24,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (BRAINPOOLP224R1_SUPPORT == ENABLED)

/**
 * @brief brainpoolP224r1 elliptic curve
 **/

const EcCurveInfo brainpoolP224r1Curve =
{
   //Curve name
   "brainpoolP224r1",
   //Object identifier
   BRAINPOOLP224R1_OID,
   sizeof(BRAINPOOLP224R1_OID),
   //Curve type
   EC_CURVE_TYPE_BRAINPOOLP_R1,
   //Prime modulus p
   {0xD7, 0xC1, 0x34, 0xAA, 0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25, 0x75, 0xD1, 0xD7, 0x87,
    0xB0, 0x9F, 0x07, 0x57, 0x97, 0xDA, 0x89, 0xF5, 0x7E, 0xC8, 0xC0, 0xFF},
   28,
   //Curve parameter a
   {0x68, 0xA5, 0xE6, 0x2C, 0xA9, 0xCE, 0x6C, 0x1C, 0x29, 0x98, 0x03, 0xA6, 0xC1, 0x53, 0x0B, 0x51,
    0x4E, 0x18, 0x2A, 0xD8, 0xB0, 0x04, 0x2A, 0x59, 0xCA, 0xD2, 0x9F, 0x43},
   28,
   //Curve parameter b
   {0x25, 0x80, 0xF6, 0x3C, 0xCF, 0xE4, 0x41, 0x38, 0x87, 0x07, 0x13, 0xB1, 0xA9, 0x23, 0x69, 0xE3,
    0x3E, 0x21, 0x35, 0xD2, 0x66, 0xDB, 0xB3, 0x72, 0x38, 0x6C, 0x40, 0x0B},
   28,
   //x-coordinate of the base point G
   {0x0D, 0x90, 0x29, 0xAD, 0x2C, 0x7E, 0x5C, 0xF4, 0x34, 0x08, 0x23, 0xB2, 0xA8, 0x7D, 0xC6, 0x8C,
    0x9E, 0x4C, 0xE3, 0x17, 0x4C, 0x1E, 0x6E, 0xFD, 0xEE, 0x12, 0xC0, 0x7D},
   28,
   //y-coordinate of the base point G
   {0x58, 0xAA, 0x56, 0xF7, 0x72, 0xC0, 0x72, 0x6F, 0x24, 0xC6, 0xB8, 0x9E, 0x4E, 0xCD, 0xAC, 0x24,
    0x35, 0x4B, 0x9E, 0x99, 0xCA, 0xA3, 0xF6, 0xD3, 0x76, 0x14, 0x02, 0xCD},
   28,
   //Base point order q
   {0xD7, 0xC1, 0x34, 0xAA, 0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25, 0x75, 0xD0, 0xFB, 0x98,
    0xD1, 0x16, 0xBC, 0x4B, 0x6D, 0xDE, 0xBC, 0xA3, 0xA5, 0xA7, 0x93, 0x9F},
   28,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (BRAINPOOLP256R1_SUPPORT == ENABLED)

/**
 * @brief brainpoolP256r1 elliptic curve
 **/

const EcCurveInfo brainpoolP256r1Curve =
{
   //Curve name
   "brainpoolP256r1",
   //Object identifier
   BRAINPOOLP256R1_OID,
   sizeof(BRAINPOOLP256R1_OID),
   //Curve type
   EC_CURVE_TYPE_BRAINPOOLP_R1,
   //Prime modulus p
   {0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC, 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
    0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28, 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x77},
   32,
   //Curve parameter a
   {0x7D, 0x5A, 0x09, 0x75, 0xFC, 0x2C, 0x30, 0x57, 0xEE, 0xF6, 0x75, 0x30, 0x41, 0x7A, 0xFF, 0xE7,
    0xFB, 0x80, 0x55, 0xC1, 0x26, 0xDC, 0x5C, 0x6C, 0xE9, 0x4A, 0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9},
   32,
   //Curve parameter b
   {0x26, 0xDC, 0x5C, 0x6C, 0xE9, 0x4A, 0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9, 0xBB, 0xD7, 0x7C, 0xBF,
    0x95, 0x84, 0x16, 0x29, 0x5C, 0xF7, 0xE1, 0xCE, 0x6B, 0xCC, 0xDC, 0x18, 0xFF, 0x8C, 0x07, 0xB6},
   32,
   //x-coordinate of the base point G
   {0x8B, 0xD2, 0xAE, 0xB9, 0xCB, 0x7E, 0x57, 0xCB, 0x2C, 0x4B, 0x48, 0x2F, 0xFC, 0x81, 0xB7, 0xAF,
    0xB9, 0xDE, 0x27, 0xE1, 0xE3, 0xBD, 0x23, 0xC2, 0x3A, 0x44, 0x53, 0xBD, 0x9A, 0xCE, 0x32, 0x62},
   32,
   //y-coordinate of the base point G
   {0x54, 0x7E, 0xF8, 0x35, 0xC3, 0xDA, 0xC4, 0xFD, 0x97, 0xF8, 0x46, 0x1A, 0x14, 0x61, 0x1D, 0xC9,
    0xC2, 0x77, 0x45, 0x13, 0x2D, 0xED, 0x8E, 0x54, 0x5C, 0x1D, 0x54, 0xC7, 0x2F, 0x04, 0x69, 0x97},
   32,
   //Base point order q
   {0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC, 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
    0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7, 0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7},
   32,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (BRAINPOOLP320R1_SUPPORT == ENABLED)

/**
 * @brief brainpoolP320r1 elliptic curve
 **/

const EcCurveInfo brainpoolP320r1Curve =
{
   //Curve name
   "brainpoolP320r1",
   //Object identifier
   BRAINPOOLP320R1_OID,
   sizeof(BRAINPOOLP320R1_OID),
   //Curve type
   EC_CURVE_TYPE_BRAINPOOLP_R1,
   //Prime modulus p
   {0xD3, 0x5E, 0x47, 0x20, 0x36, 0xBC, 0x4F, 0xB7, 0xE1, 0x3C, 0x78, 0x5E, 0xD2, 0x01, 0xE0, 0x65,
    0xF9, 0x8F, 0xCF, 0xA6, 0xF6, 0xF4, 0x0D, 0xEF, 0x4F, 0x92, 0xB9, 0xEC, 0x78, 0x93, 0xEC, 0x28,
    0xFC, 0xD4, 0x12, 0xB1, 0xF1, 0xB3, 0x2E, 0x27},
   40,
   //Curve parameter a
   {0x3E, 0xE3, 0x0B, 0x56, 0x8F, 0xBA, 0xB0, 0xF8, 0x83, 0xCC, 0xEB, 0xD4, 0x6D, 0x3F, 0x3B, 0xB8,
    0xA2, 0xA7, 0x35, 0x13, 0xF5, 0xEB, 0x79, 0xDA, 0x66, 0x19, 0x0E, 0xB0, 0x85, 0xFF, 0xA9, 0xF4,
    0x92, 0xF3, 0x75, 0xA9, 0x7D, 0x86, 0x0E, 0xB4},
   40,
   //Curve parameter b
   {0x52, 0x08, 0x83, 0x94, 0x9D, 0xFD, 0xBC, 0x42, 0xD3, 0xAD, 0x19, 0x86, 0x40, 0x68, 0x8A, 0x6F,
    0xE1, 0x3F, 0x41, 0x34, 0x95, 0x54, 0xB4, 0x9A, 0xCC, 0x31, 0xDC, 0xCD, 0x88, 0x45, 0x39, 0x81,
    0x6F, 0x5E, 0xB4, 0xAC, 0x8F, 0xB1, 0xF1, 0xA6},
   40,
   //x-coordinate of the base point G
   {0x43, 0xBD, 0x7E, 0x9A, 0xFB, 0x53, 0xD8, 0xB8, 0x52, 0x89, 0xBC, 0xC4, 0x8E, 0xE5, 0xBF, 0xE6,
    0xF2, 0x01, 0x37, 0xD1, 0x0A, 0x08, 0x7E, 0xB6, 0xE7, 0x87, 0x1E, 0x2A, 0x10, 0xA5, 0x99, 0xC7,
    0x10, 0xAF, 0x8D, 0x0D, 0x39, 0xE2, 0x06, 0x11},
   40,
   //y-coordinate of the base point G
   {0x14, 0xFD, 0xD0, 0x55, 0x45, 0xEC, 0x1C, 0xC8, 0xAB, 0x40, 0x93, 0x24, 0x7F, 0x77, 0x27, 0x5E,
    0x07, 0x43, 0xFF, 0xED, 0x11, 0x71, 0x82, 0xEA, 0xA9, 0xC7, 0x78, 0x77, 0xAA, 0xAC, 0x6A, 0xC7,
    0xD3, 0x52, 0x45, 0xD1, 0x69, 0x2E, 0x8E, 0xE1},
   40,
   //Base point order q
   {0xD3, 0x5E, 0x47, 0x20, 0x36, 0xBC, 0x4F, 0xB7, 0xE1, 0x3C, 0x78, 0x5E, 0xD2, 0x01, 0xE0, 0x65,
    0xF9, 0x8F, 0xCF, 0xA5, 0xB6, 0x8F, 0x12, 0xA3, 0x2D, 0x48, 0x2E, 0xC7, 0xEE, 0x86, 0x58, 0xE9,
    0x86, 0x91, 0x55, 0x5B, 0x44, 0xC5, 0x93, 0x11},
   40,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (BRAINPOOLP384R1_SUPPORT == ENABLED)

/**
 * @brief brainpoolP384r1 elliptic curve
 **/

const EcCurveInfo brainpoolP384r1Curve =
{
   //Curve name
   "brainpoolP384r1",
   //Object identifier
   BRAINPOOLP384R1_OID,
   sizeof(BRAINPOOLP384R1_OID),
   //Curve type
   EC_CURVE_TYPE_BRAINPOOLP_R1,
   //Prime modulus p
   {0x8C, 0xB9, 0x1E, 0x82, 0xA3, 0x38, 0x6D, 0x28, 0x0F, 0x5D, 0x6F, 0x7E, 0x50, 0xE6, 0x41, 0xDF,
    0x15, 0x2F, 0x71, 0x09, 0xED, 0x54, 0x56, 0xB4, 0x12, 0xB1, 0xDA, 0x19, 0x7F, 0xB7, 0x11, 0x23,
    0xAC, 0xD3, 0xA7, 0x29, 0x90, 0x1D, 0x1A, 0x71, 0x87, 0x47, 0x00, 0x13, 0x31, 0x07, 0xEC, 0x53},
   48,
   //Curve parameter a
   {0x7B, 0xC3, 0x82, 0xC6, 0x3D, 0x8C, 0x15, 0x0C, 0x3C, 0x72, 0x08, 0x0A, 0xCE, 0x05, 0xAF, 0xA0,
    0xC2, 0xBE, 0xA2, 0x8E, 0x4F, 0xB2, 0x27, 0x87, 0x13, 0x91, 0x65, 0xEF, 0xBA, 0x91, 0xF9, 0x0F,
    0x8A, 0xA5, 0x81, 0x4A, 0x50, 0x3A, 0xD4, 0xEB, 0x04, 0xA8, 0xC7, 0xDD, 0x22, 0xCE, 0x28, 0x26},
   48,
   //Curve parameter b
   {0x04, 0xA8, 0xC7, 0xDD, 0x22, 0xCE, 0x28, 0x26, 0x8B, 0x39, 0xB5, 0x54, 0x16, 0xF0, 0x44, 0x7C,
    0x2F, 0xB7, 0x7D, 0xE1, 0x07, 0xDC, 0xD2, 0xA6, 0x2E, 0x88, 0x0E, 0xA5, 0x3E, 0xEB, 0x62, 0xD5,
    0x7C, 0xB4, 0x39, 0x02, 0x95, 0xDB, 0xC9, 0x94, 0x3A, 0xB7, 0x86, 0x96, 0xFA, 0x50, 0x4C, 0x11},
   48,
   //x-coordinate of the base point G
   {0x1D, 0x1C, 0x64, 0xF0, 0x68, 0xCF, 0x45, 0xFF, 0xA2, 0xA6, 0x3A, 0x81, 0xB7, 0xC1, 0x3F, 0x6B,
    0x88, 0x47, 0xA3, 0xE7, 0x7E, 0xF1, 0x4F, 0xE3, 0xDB, 0x7F, 0xCA, 0xFE, 0x0C, 0xBD, 0x10, 0xE8,
    0xE8, 0x26, 0xE0, 0x34, 0x36, 0xD6, 0x46, 0xAA, 0xEF, 0x87, 0xB2, 0xE2, 0x47, 0xD4, 0xAF, 0x1E},
   48,
   //y-coordinate of the base point G
   {0x8A, 0xBE, 0x1D, 0x75, 0x20, 0xF9, 0xC2, 0xA4, 0x5C, 0xB1, 0xEB, 0x8E, 0x95, 0xCF, 0xD5, 0x52,
    0x62, 0xB7, 0x0B, 0x29, 0xFE, 0xEC, 0x58, 0x64, 0xE1, 0x9C, 0x05, 0x4F, 0xF9, 0x91, 0x29, 0x28,
    0x0E, 0x46, 0x46, 0x21, 0x77, 0x91, 0x81, 0x11, 0x42, 0x82, 0x03, 0x41, 0x26, 0x3C, 0x53, 0x15},
   48,
   //Base point order q
   {0x8C, 0xB9, 0x1E, 0x82, 0xA3, 0x38, 0x6D, 0x28, 0x0F, 0x5D, 0x6F, 0x7E, 0x50, 0xE6, 0x41, 0xDF,
    0x15, 0x2F, 0x71, 0x09, 0xED, 0x54, 0x56, 0xB3, 0x1F, 0x16, 0x6E, 0x6C, 0xAC, 0x04, 0x25, 0xA7,
    0xCF, 0x3A, 0xB6, 0xAF, 0x6B, 0x7F, 0xC3, 0x10, 0x3B, 0x88, 0x32, 0x02, 0xE9, 0x04, 0x65, 0x65},
   48,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (BRAINPOOLP512R1_SUPPORT == ENABLED)

/**
 * @brief brainpoolP512r1 elliptic curve
 **/

const EcCurveInfo brainpoolP512r1Curve =
{
   //Curve name
   "brainpoolP512r1",
   //Object identifier
   BRAINPOOLP512R1_OID,
   sizeof(BRAINPOOLP512R1_OID),
   //Curve type
   EC_CURVE_TYPE_BRAINPOOLP_R1,
   //Prime modulus p
   {0xAA, 0xDD, 0x9D, 0xB8, 0xDB, 0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6, 0xAE, 0x33, 0xC9, 0xFC, 0x07,
    0xCB, 0x30, 0x8D, 0xB3, 0xB3, 0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C, 0xCA, 0x70, 0x33, 0x08, 0x71,
    0x7D, 0x4D, 0x9B, 0x00, 0x9B, 0xC6, 0x68, 0x42, 0xAE, 0xCD, 0xA1, 0x2A, 0xE6, 0xA3, 0x80, 0xE6,
    0x28, 0x81, 0xFF, 0x2F, 0x2D, 0x82, 0xC6, 0x85, 0x28, 0xAA, 0x60, 0x56, 0x58, 0x3A, 0x48, 0xF3},
   64,
   //Curve parameter a
   {0x78, 0x30, 0xA3, 0x31, 0x8B, 0x60, 0x3B, 0x89, 0xE2, 0x32, 0x71, 0x45, 0xAC, 0x23, 0x4C, 0xC5,
    0x94, 0xCB, 0xDD, 0x8D, 0x3D, 0xF9, 0x16, 0x10, 0xA8, 0x34, 0x41, 0xCA, 0xEA, 0x98, 0x63, 0xBC,
    0x2D, 0xED, 0x5D, 0x5A, 0xA8, 0x25, 0x3A, 0xA1, 0x0A, 0x2E, 0xF1, 0xC9, 0x8B, 0x9A, 0xC8, 0xB5,
    0x7F, 0x11, 0x17, 0xA7, 0x2B, 0xF2, 0xC7, 0xB9, 0xE7, 0xC1, 0xAC, 0x4D, 0x77, 0xFC, 0x94, 0xCA},
   64,
   //Curve parameter b
   {0x3D, 0xF9, 0x16, 0x10, 0xA8, 0x34, 0x41, 0xCA, 0xEA, 0x98, 0x63, 0xBC, 0x2D, 0xED, 0x5D, 0x5A,
    0xA8, 0x25, 0x3A, 0xA1, 0x0A, 0x2E, 0xF1, 0xC9, 0x8B, 0x9A, 0xC8, 0xB5, 0x7F, 0x11, 0x17, 0xA7,
    0x2B, 0xF2, 0xC7, 0xB9, 0xE7, 0xC1, 0xAC, 0x4D, 0x77, 0xFC, 0x94, 0xCA, 0xDC, 0x08, 0x3E, 0x67,
    0x98, 0x40, 0x50, 0xB7, 0x5E, 0xBA, 0xE5, 0xDD, 0x28, 0x09, 0xBD, 0x63, 0x80, 0x16, 0xF7, 0x23},
   64,
   //x-coordinate of the base point G
   {0x81, 0xAE, 0xE4, 0xBD, 0xD8, 0x2E, 0xD9, 0x64, 0x5A, 0x21, 0x32, 0x2E, 0x9C, 0x4C, 0x6A, 0x93,
    0x85, 0xED, 0x9F, 0x70, 0xB5, 0xD9, 0x16, 0xC1, 0xB4, 0x3B, 0x62, 0xEE, 0xF4, 0xD0, 0x09, 0x8E,
    0xFF, 0x3B, 0x1F, 0x78, 0xE2, 0xD0, 0xD4, 0x8D, 0x50, 0xD1, 0x68, 0x7B, 0x93, 0xB9, 0x7D, 0x5F,
    0x7C, 0x6D, 0x50, 0x47, 0x40, 0x6A, 0x5E, 0x68, 0x8B, 0x35, 0x22, 0x09, 0xBC, 0xB9, 0xF8, 0x22},
   64,
   //y-coordinate of the base point G
   {0x7D, 0xDE, 0x38, 0x5D, 0x56, 0x63, 0x32, 0xEC, 0xC0, 0xEA, 0xBF, 0xA9, 0xCF, 0x78, 0x22, 0xFD,
    0xF2, 0x09, 0xF7, 0x00, 0x24, 0xA5, 0x7B, 0x1A, 0xA0, 0x00, 0xC5, 0x5B, 0x88, 0x1F, 0x81, 0x11,
    0xB2, 0xDC, 0xDE, 0x49, 0x4A, 0x5F, 0x48, 0x5E, 0x5B, 0xCA, 0x4B, 0xD8, 0x8A, 0x27, 0x63, 0xAE,
    0xD1, 0xCA, 0x2B, 0x2F, 0xA8, 0xF0, 0x54, 0x06, 0x78, 0xCD, 0x1E, 0x0F, 0x3A, 0xD8, 0x08, 0x92},
   64,
   //Base point order q
   {0xAA, 0xDD, 0x9D, 0xB8, 0xDB, 0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6, 0xAE, 0x33, 0xC9, 0xFC, 0x07,
    0xCB, 0x30, 0x8D, 0xB3, 0xB3, 0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C, 0xCA, 0x70, 0x33, 0x08, 0x70,
    0x55, 0x3E, 0x5C, 0x41, 0x4C, 0xA9, 0x26, 0x19, 0x41, 0x86, 0x61, 0x19, 0x7F, 0xAC, 0x10, 0x47,
    0x1D, 0xB1, 0xD3, 0x81, 0x08, 0x5D, 0xDA, 0xDD, 0xB5, 0x87, 0x96, 0x82, 0x9C, 0xA9, 0x00, 0x69},
   64,
   //Cofactor
   1,
   //Fast modular reduction
   NULL
};

#endif
#if (CURVE25519_SUPPORT == ENABLED)

/**
 * @brief Curve25519 elliptic curve
 **/

const EcCurveInfo x25519Curve =
{
   //Curve name
   "Curve22519",
   //Object identifier
   X25519_OID,
   sizeof(X25519_OID),
   //Curve type
   EC_CURVE_TYPE_X25519,
   //Prime modulus p
   {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xED},
   32,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x6D, 0x06},
   32,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   32,
   //u-coordinate of the base point G
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09},
   32,
   //v-coordinate of the base point G
   {0x20, 0xAE, 0x19, 0xA1, 0xB8, 0xA0, 0x86, 0xB4, 0xE0, 0x1E, 0xDD, 0x2C, 0x77, 0x48, 0xD1, 0x4C,
    0x92, 0x3D, 0x4D, 0x7E, 0x6D, 0x7C, 0x61, 0xB2, 0x29, 0xE9, 0xC5, 0xA2, 0x7E, 0xCE, 0xD3, 0xD9},
   32,
   //Base point order q
   {0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED},
   32,
   //Cofactor
   8,
   //Fast modular reduction
   NULL
};

#endif
#if (CURVE448_SUPPORT == ENABLED)

/**
 * @brief Curve448 elliptic curve
 **/

const EcCurveInfo x448Curve =
{
   //Curve name
   "Curve448",
   //Object identifier
   X448_OID,
   sizeof(X448_OID),
   //Curve type
   EC_CURVE_TYPE_X448,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
   56,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x62, 0xA6},
   56,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   56,
   //u-coordinate of the base point G
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05},
   56,
   //v-coordinate of the base point G
   {0x7D, 0x23, 0x5D, 0x12, 0x95, 0xF5, 0xB1, 0xF6, 0x6C, 0x98, 0xAB, 0x6E, 0x58, 0x32, 0x6F, 0xCE,
    0xCB, 0xAE, 0x5D, 0x34, 0xF5, 0x55, 0x45, 0xD0, 0x60, 0xF7, 0x5D, 0xC2, 0x8D, 0xF3, 0xF6, 0xED,
    0xB8, 0x02, 0x7E, 0x23, 0x46, 0x43, 0x0D, 0x21, 0x13, 0x12, 0xC4, 0xB1, 0x50, 0x67, 0x7A, 0xF7,
    0x6F, 0xD7, 0x22, 0x3D, 0x45, 0x7B, 0x5B, 0x1A},
   56,
   //Base point order q
   {0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7C, 0xCA, 0x23, 0xE9,
    0xC4, 0x4E, 0xDB, 0x49, 0xAE, 0xD6, 0x36, 0x90, 0x21, 0x6C, 0xC2, 0x72, 0x8D, 0xC5, 0x8F, 0x55,
    0x23, 0x78, 0xC2, 0x92, 0xAB, 0x58, 0x44, 0xF3},
   56,
   //Cofactor
   4,
   //Fast modular reduction
   NULL
};

#endif
#if (ED25519_SUPPORT == ENABLED)

/**
 * @brief Ed25519 elliptic curve
 **/

const EcCurveInfo ed25519Curve =
{
   //Curve name
   "Ed22519",
   //Object identifier
   ED25519_OID,
   sizeof(ED25519_OID),
   //Curve type
   EC_CURVE_TYPE_ED25519,
   //Prime modulus p
   {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xED},
   32,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x6D, 0x06},
   32,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   32,
   //x-coordinate of the base point G
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09},
   32,
   //y-coordinate of the base point G
   {0x20, 0xAE, 0x19, 0xA1, 0xB8, 0xA0, 0x86, 0xB4, 0xE0, 0x1E, 0xDD, 0x2C, 0x77, 0x48, 0xD1, 0x4C,
    0x92, 0x3D, 0x4D, 0x7E, 0x6D, 0x7C, 0x61, 0xB2, 0x29, 0xE9, 0xC5, 0xA2, 0x7E, 0xCE, 0xD3, 0xD9},
   32,
   //Base point order q
   {0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED},
   32,
   //Cofactor
   8,
   //Fast modular reduction
   NULL
};

#endif
#if (ED448_SUPPORT == ENABLED)

/**
 * @brief Ed448 elliptic curve
 **/

const EcCurveInfo ed448Curve =
{
   //Curve name
   "Ed448",
   //Object identifier
   ED448_OID,
   sizeof(ED448_OID),
   //Curve type
   EC_CURVE_TYPE_ED448,
   //Prime modulus p
   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
   56,
   //Curve parameter a
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x62, 0xA6},
   56,
   //Curve parameter b
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   56,
   //x-coordinate of the base point G
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05},
   56,
   //y-coordinate of the base point G
   {0x7D, 0x23, 0x5D, 0x12, 0x95, 0xF5, 0xB1, 0xF6, 0x6C, 0x98, 0xAB, 0x6E, 0x58, 0x32, 0x6F, 0xCE,
    0xCB, 0xAE, 0x5D, 0x34, 0xF5, 0x55, 0x45, 0xD0, 0x60, 0xF7, 0x5D, 0xC2, 0x8D, 0xF3, 0xF6, 0xED,
    0xB8, 0x02, 0x7E, 0x23, 0x46, 0x43, 0x0D, 0x21, 0x13, 0x12, 0xC4, 0xB1, 0x50, 0x67, 0x7A, 0xF7,
    0x6F, 0xD7, 0x22, 0x3D, 0x45, 0x7B, 0x5B, 0x1A},
   56,
   //Base point order q
   {0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7C, 0xCA, 0x23, 0xE9,
    0xC4, 0x4E, 0xDB, 0x49, 0xAE, 0xD6, 0x36, 0x90, 0x21, 0x6C, 0xC2, 0x72, 0x8D, 0xC5, 0x8F, 0x55,
    0x23, 0x78, 0xC2, 0x92, 0xAB, 0x58, 0x44, 0xF3},
   56,
   //Cofactor
   4,
   //Fast modular reduction
   NULL
};

#endif
#if (SECP128R1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp128r1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp128r1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 32 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = 0 | 0 | 0 | 0 | A7 | A6 | A5 | A4
      COPY_WORD32(&t, 0, a, 4, 4);
      CLEAR_WORD32(&t, 4, 4);

      //Clear A7 | A6 | A5 | A4
      CLEAR_WORD32(a, 4, 4);

      //Compute A = A + T + (T << 97)
      MPI_CHECK(mpiAdd(a, a, &t));
      MPI_CHECK(mpiShiftLeft(&t, 97));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP128R2_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp128r2 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp128r2Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 32 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = 0 | 0 | 0 | 0 | A7 | A6 | A5 | A4
      COPY_WORD32(&t, 0, a, 4, 4);
      CLEAR_WORD32(&t, 4, 4);

      //Clear A7 | A6 | A5 | A4
      CLEAR_WORD32(a, 4, 4);

      //Compute A = A + T + (T << 97)
      MPI_CHECK(mpiAdd(a, a, &t));
      MPI_CHECK(mpiShiftLeft(&t, 97));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP160K1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp160k1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp160k1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 40 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = A9 | A8 | A7 | A6 | A5 | 0
      CLEAR_WORD32(&t, 0, 1);
      COPY_WORD32(&t, 1, a, 5, 5);

      //Clear A9 | A8 | A7 | A6 | A5
      CLEAR_WORD32(a, 5, 5);

      //Compute A = A + T
      MPI_CHECK(mpiAdd(a, a, &t));
      //Compute T = T >> 32
      MPI_CHECK(mpiShiftRight(&t, 32));
      //Compute A = A + (21389 * T)
      MPI_CHECK(mpiMulInt(&t, &t, 21389));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP160R1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp160r1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp160r1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 40 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = 0 | A9 | A8 | A7 | A6 | A5
      COPY_WORD32(&t, 0, a, 5, 5);
      CLEAR_WORD32(&t, 5, 1);

      //Clear A9 | A8 | A7 | A6 | A5
      CLEAR_WORD32(a, 5, 5);

      //Compute A = A + T + (T << 31)
      MPI_CHECK(mpiAdd(a, a, &t));
      MPI_CHECK(mpiShiftLeft(&t, 31));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP160R2_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp160r2 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp160r2Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 40 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = A9 | A8 | A7 | A6 | A5 | 0
      CLEAR_WORD32(&t, 0, 1);
      COPY_WORD32(&t, 1, a, 5, 5);

      //Clear A9 | A8 | A7 | A6 | A5
      CLEAR_WORD32(a, 5, 5);

      //Compute A = A + T
      MPI_CHECK(mpiAdd(a, a, &t));
      //Compute T = T >> 32
      MPI_CHECK(mpiShiftRight(&t, 32));
      //Compute A = A + (21389 * T)
      MPI_CHECK(mpiMulInt(&t, &t, 21389));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP192K1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp192k1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp192k1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 48 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 28 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = A11 | A10 | A9 | A8 | A7 | A6 | 0
      CLEAR_WORD32(&t, 0, 1);
      COPY_WORD32(&t, 1, a, 6, 6);

      //Clear A11 | A10 | A9 | A8 | A7 | A6
      CLEAR_WORD32(a, 6, 6);

      //Compute A = A + T
      MPI_CHECK(mpiAdd(a, a, &t));
      //Compute T = T >> 32
      MPI_CHECK(mpiShiftRight(&t, 32));
      //Compute A = A + (4553 * T)
      MPI_CHECK(mpiMulInt(&t, &t, 4553));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP192R1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp192r1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp192r1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi s;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&s);
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 48 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&s, 24 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));

   //Compute T = A5 | A4 | A3 | A2 | A1 | A0
   COPY_WORD32(&t, 0, a, 0, 6);

   //Compute S1 = 0 | 0 | A7 | A6 | A7 | A6
   COPY_WORD32(&s, 0, a, 6, 2);
   COPY_WORD32(&s, 2, a, 6, 2);
   CLEAR_WORD32(&s, 4, 2);
   //Compute T = T + S1
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S2 = A9 | A8 | A9 | A8 | 0 | 0
   CLEAR_WORD32(&s, 0, 2);
   COPY_WORD32(&s, 2, a, 8, 2);
   COPY_WORD32(&s, 4, a, 8, 2);
   //Compute T = T + S2
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S3 = A11 | A10 | A11 | A10 | A11 | A10
   COPY_WORD32(&s, 0, a, 10, 2);
   COPY_WORD32(&s, 2, a, 10, 2);
   COPY_WORD32(&s, 4, a, 10, 2);
   //Compute T = T + S3
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute (T + S1 + S2 + S3) mod p
   while(mpiComp(&t, p) >= 0)
   {
      MPI_CHECK(mpiSub(&t, &t, p));
   }

   //Save result
   MPI_CHECK(mpiCopy(a, &t));

end:
   //Release multiple precision integers
   mpiFree(&s);
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP224K1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp224k1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp224k1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 56 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = A13 | A12 | A11 | A10 | A9 | A8 | A7 | 0
      CLEAR_WORD32(&t, 0, 1);
      COPY_WORD32(&t, 1, a, 7, 7);

      //Clear A13 | A12 | A11 | A10 | A9 | A8 | A7
      CLEAR_WORD32(a, 7, 7);

      //Compute A = A + T
      MPI_CHECK(mpiAdd(a, a, &t));
      //Compute T = T >> 32
      MPI_CHECK(mpiShiftRight(&t, 32));
      //Compute A = A + (6803 * T)
      MPI_CHECK(mpiMulInt(&t, &t, 6803));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP224R1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp224r1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp224r1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi s;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&s);
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 56 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&s, 28 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 28 / MPI_INT_SIZE));

   //Compute T = A6 | A5 | A4 | A3 | A2 | A1 | A0
   COPY_WORD32(&t, 0, a, 0, 7);

   //Compute S1 = A10 | A9 | A8 | A7 | 0 | 0 | 0
   CLEAR_WORD32(&s, 0, 3);
   COPY_WORD32(&s, 3, a, 7, 4);
   //Compute T = T + S1
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S2 = 0 | A13 | A12 | A11 | 0 | 0 | 0
   CLEAR_WORD32(&s, 0, 3);
   COPY_WORD32(&s, 3, a, 11, 3);
   CLEAR_WORD32(&s, 6, 1);
   //Compute T = T + S2
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute D1 = A13 | A12 | A11 | A10 | A9 | A8 | A7
   COPY_WORD32(&s, 0, a, 7, 7);
   //Compute T = T - D1
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute D2 = 0 | 0 | 0 | 0 | A13 | A12 | A11
   COPY_WORD32(&s, 0, a, 11, 3);
   CLEAR_WORD32(&s, 3, 4);
   //Compute T = T - D2
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute (T + S1 + S2 - D1 - D2) mod p
   while(mpiComp(&t, p) >= 0)
   {
      MPI_CHECK(mpiSub(&t, &t, p));
   }

   while(mpiCompInt(&t, 0) < 0)
   {
      MPI_CHECK(mpiAdd(&t, &t, p));
   }

   //Save result
   MPI_CHECK(mpiCopy(a, &t));

end:
   //Release multiple precision integers
   mpiFree(&s);
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP256K1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp256k1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp256k1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 64 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 36 / MPI_INT_SIZE));

   //Perform modular reduction
   do
   {
      //Compute T = A15 | A14 | A13 | A12 | A11 | A10 | A9 | A8 | 0
      CLEAR_WORD32(&t, 0, 1);
      COPY_WORD32(&t, 1, a, 8, 8);

      //Clear A15 | A14 | A13 | A12 | A11 | A10 | A9 | A8
      CLEAR_WORD32(a, 8, 8);

      //Compute A = A + T
      MPI_CHECK(mpiAdd(a, a, &t));
      //Compute T = T >> 32
      MPI_CHECK(mpiShiftRight(&t, 32));
      //Compute A = A + (977 * T)
      MPI_CHECK(mpiMulInt(&t, &t, 977));
      MPI_CHECK(mpiAdd(a, a, &t));

      //Check for end condition
   } while(mpiComp(a, p) > 0);

end:
   //Release multiple precision integers
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP256R1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp256r1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp256r1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi s;
   Mpi t;
   Mpi b;

   //Initialize multiple precision integers
   mpiInit(&s);
   mpiInit(&t);
   mpiInit(&b);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 64 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&s, 32 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));

   //Compute T = A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0
   COPY_WORD32(&t, 0, a, 0, 8);

   //Compute S1 = A15 | A14 | A13 | A12 | A11 | 0 | 0 | 0
   CLEAR_WORD32(&s, 0, 3);
   COPY_WORD32(&s, 3, a, 11, 5);
   //Compute T = T + 2 * S1
   MPI_CHECK(mpiAdd(&t, &t, &s));
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S2 = 0 | A15 | A14 | A13 | A12 | 0 | 0 | 0
   CLEAR_WORD32(&s, 0, 3);
   COPY_WORD32(&s, 3, a, 12, 4);
   CLEAR_WORD32(&s, 7, 1);
   //Compute T = T + 2 * S2
   MPI_CHECK(mpiAdd(&t, &t, &s));
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S3 = A15 | A14 | 0 | 0 | 0 | A10 | A9 | A8
   COPY_WORD32(&s, 0, a, 8, 3);
   CLEAR_WORD32(&s, 3, 3);
   COPY_WORD32(&s, 6, a, 14, 2);
   //Compute T = T + S3
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S4 = A8 | A13 | A15 | A14 | A13 | A11 | A10 | A9
   COPY_WORD32(&s, 0, a, 9, 3);
   COPY_WORD32(&s, 3, a, 13, 3);
   COPY_WORD32(&s, 6, a, 13, 1);
   COPY_WORD32(&s, 7, a, 8, 1);
   //Compute T = T + S4
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute D1 = A10 | A8 | 0 | 0 | 0 | A13 | A12 | A11
   COPY_WORD32(&s, 0, a, 11, 3);
   CLEAR_WORD32(&s, 3, 3);
   COPY_WORD32(&s, 6, a, 8, 1);
   COPY_WORD32(&s, 7, a, 10, 1);
   //Compute T = T - D1
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute D2 = A11 | A9 | 0 | 0 | A15 | A14 | A13 | A12
   COPY_WORD32(&s, 0, a, 12, 4);
   CLEAR_WORD32(&s, 4, 2);
   COPY_WORD32(&s, 6, a, 9, 1);
   COPY_WORD32(&s, 7, a, 11, 1);
   //Compute T = T - D2
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute D3 = A12 | 0 | A10 | A9 | A8 | A15 | A14 | A13
   COPY_WORD32(&s, 0, a, 13, 3);
   COPY_WORD32(&s, 3, a, 8, 3);
   CLEAR_WORD32(&s, 6, 1);
   COPY_WORD32(&s, 7, a, 12, 1);
   //Compute T = T - D3
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute D4 = A13 | 0 | A11 | A10 | A9 | 0 | A15 | A14
   COPY_WORD32(&s, 0, a, 14, 2);
   CLEAR_WORD32(&s, 2, 1);
   COPY_WORD32(&s, 3, a, 9, 3);
   CLEAR_WORD32(&s, 6, 1);
   COPY_WORD32(&s, 7, a, 13, 1);
   //Compute T = T - D4
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute (T + 2 * S1 + 2 * S2 + S3 + S4 - D1 - D2 - D3 - D4) mod p
   while(mpiComp(&t, p) >= 0)
   {
      MPI_CHECK(mpiSub(&t, &t, p));
   }

   while(mpiCompInt(&t, 0) < 0)
   {
      MPI_CHECK(mpiAdd(&t, &t, p));
   }

   //Save result
   MPI_CHECK(mpiCopy(a, &t));

end:
   //Release multiple precision integers
   mpiFree(&s);
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP384R1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp384r1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp384r1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi s;
   Mpi t;

   //Initialize multiple precision integers
   mpiInit(&s);
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 96 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&s, 48 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 48 / MPI_INT_SIZE));

   //Compute T = A11 | A10 | A9 | A8 | A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0
   COPY_WORD32(&t, 0, a, 0, 12);

   //Compute S1 = 0 | 0 | 0 | 0 | 0 | A23 | A22 | A21 | 0 | 0 | 0 | 0
   CLEAR_WORD32(&s, 0, 4);
   COPY_WORD32(&s, 4, a, 21, 3);
   CLEAR_WORD32(&s, 7, 5);
   //Compute T = T + 2 * S1
   MPI_CHECK(mpiAdd(&t, &t, &s));
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S2 = A23 | A22 | A21 | A20 | A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12
   COPY_WORD32(&s, 0, a, 12, 12);
   //Compute T = T + S2
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S3 = A20 | A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 | A23| A22 | A21
   COPY_WORD32(&s, 0, a, 21, 3);
   COPY_WORD32(&s, 3, a, 12, 9);
   //Compute T = T + S3
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S4 = A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 | A20 | 0 | A23 | 0
   CLEAR_WORD32(&s, 0, 1);
   COPY_WORD32(&s, 1, a, 23, 1);
   CLEAR_WORD32(&s, 2, 1);
   COPY_WORD32(&s, 3, a, 20, 1);
   COPY_WORD32(&s, 4, a, 12, 8);
   //Compute T = T + S4
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S5 = 0 | 0 | 0 | 0 | A23 | A22 | A21 | A20 | 0 | 0 | 0 | 0
   CLEAR_WORD32(&s, 0, 4);
   COPY_WORD32(&s, 4, a, 20, 4);
   CLEAR_WORD32(&s, 8, 4);
   //Compute T = T + S5
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute S6 = 0 | 0 | 0 | 0 | 0 | 0 | A23 | A22 | A21 | 0 | 0 | A20
   COPY_WORD32(&s, 0, a, 20, 1);
   CLEAR_WORD32(&s, 1, 2);
   COPY_WORD32(&s, 3, a, 21, 3);
   CLEAR_WORD32(&s, 6, 6);
   //Compute T = T + S6
   MPI_CHECK(mpiAdd(&t, &t, &s));

   //Compute D1 = A22 | A21 | A20 | A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 | A23
   COPY_WORD32(&s, 0, a, 23, 1);
   COPY_WORD32(&s, 1, a, 12, 11);
   //Compute T = T - D1
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute D2 = 0 | 0 | 0 | 0 | 0 | 0 | 0 | A23 | A22 | A21 | A20 | 0
   CLEAR_WORD32(&s, 0, 1);
   COPY_WORD32(&s, 1, a, 20, 4);
   CLEAR_WORD32(&s, 5, 7);
   //Compute T = T - D2
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute D3 = 0 | 0 | 0 | 0 | 0 | 0 | 0 | A23 | A23 | 0 | 0 | 0
   CLEAR_WORD32(&s, 0, 3);
   COPY_WORD32(&s, 3, a, 23, 1);
   COPY_WORD32(&s, 4, a, 23, 1);
   CLEAR_WORD32(&s, 5, 7);
   //Compute T = T - D3
   MPI_CHECK(mpiSub(&t, &t, &s));

   //Compute (T + 2 * S1 + S2 + S3 + S4 + S5 + S6 - D1 - D2 - D3) mod p
   while(mpiComp(&t, p) >= 0)
   {
      MPI_CHECK(mpiSub(&t, &t, p));
   }

   while(mpiCompInt(&t, 0) < 0)
   {
      MPI_CHECK(mpiAdd(&t, &t, p));
   }

   //Save result
   MPI_CHECK(mpiCopy(a, &t));

end:
   //Release multiple precision integers
   mpiFree(&s);
   mpiFree(&t);

   //Return status code
   return error;
}

#endif
#if (SECP521R1_SUPPORT == ENABLED)

/**
 * @brief Fast modular reduction (secp521r1 curve)
 * @param[in,out] a This function accept an integer less than p^2 as
 *   input and return (a mod p) as output
 * @param[in] p Prime modulus
 **/

error_t secp521r1Mod(Mpi *a, const Mpi *p)
{
   error_t error;
   Mpi t;

   //Initialize multiple precision integer
   mpiInit(&t);

   //Ajust the size of the integers
   MPI_CHECK(mpiGrow(a, 132 / MPI_INT_SIZE));
   MPI_CHECK(mpiGrow(&t, 68 / MPI_INT_SIZE));

   //Compute A0
   COPY_WORD32(&t, 0, a, 0, 17);
   t.data[16] &= 0x000001FF;

   //Compute A1
   MPI_CHECK(mpiShiftRight(a, 521));

   //Compute A0 + A1
   MPI_CHECK(mpiAdd(a, a, &t));

   //Compute (A0 + A1) mod p
   while(mpiComp(a, p) >= 0)
   {
      MPI_CHECK(mpiSub(a, a, p));
   }

end:
   //Release multiple precision integer
   mpiFree(&t);

   //Return status code
   return error;
}

#endif


/**
 * @brief Get the elliptic curve that matches the specified OID
 * @param[in] oid Object identifier
 * @param[in] length OID length
 * @return Elliptic curve domain parameters
 **/

const EcCurveInfo *ecGetCurveInfo(const uint8_t *oid, size_t length)
{
   const EcCurveInfo *curveInfo;

   //Invalid parameters?
   if(oid == NULL || length == 0)
   {
      curveInfo = NULL;
   }
#if (SECP112R1_SUPPORT == ENABLED)
   //secp112r1 elliptic curve?
   else if(!oidComp(oid, length, SECP112R1_OID, sizeof(SECP112R1_OID)))
   {
      curveInfo = SECP112R1_CURVE;
   }
#endif
#if (SECP112R2_SUPPORT == ENABLED)
   //secp112r2 elliptic curve?
   else if(!oidComp(oid, length, SECP112R2_OID, sizeof(SECP112R2_OID)))
   {
      curveInfo = SECP112R2_CURVE;
   }
#endif
#if (SECP128R1_SUPPORT == ENABLED)
   //secp128r1 elliptic curve?
   else if(!oidComp(oid, length, SECP128R1_OID, sizeof(SECP128R1_OID)))
   {
      curveInfo = SECP128R1_CURVE;
   }
#endif
#if (SECP128R2_SUPPORT == ENABLED)
   //secp128r2 elliptic curve?
   else if(!oidComp(oid, length, SECP128R2_OID, sizeof(SECP128R2_OID)))
   {
      curveInfo = SECP128R2_CURVE;
   }
#endif
#if (SECP160K1_SUPPORT == ENABLED)
   //secp160k1 elliptic curve?
   else if(!oidComp(oid, length, SECP160K1_OID, sizeof(SECP160K1_OID)))
   {
      curveInfo = SECP160K1_CURVE;
   }
#endif
#if (SECP160R1_SUPPORT == ENABLED)
   //secp160r1 elliptic curve?
   else if(!oidComp(oid, length, SECP160R1_OID, sizeof(SECP160R1_OID)))
   {
      curveInfo = SECP160R1_CURVE;
   }
#endif
#if (SECP160R2_SUPPORT == ENABLED)
   //secp160r2 elliptic curve?
   else if(!oidComp(oid, length, SECP160R2_OID, sizeof(SECP160R2_OID)))
   {
      curveInfo = SECP160R2_CURVE;
   }
#endif
#if (SECP192K1_SUPPORT == ENABLED)
   //secp192k1 elliptic curve?
   else if(!oidComp(oid, length, SECP192K1_OID, sizeof(SECP192K1_OID)))
   {
      curveInfo = SECP192K1_CURVE;
   }
#endif
#if (SECP192R1_SUPPORT == ENABLED)
   //secp192r1 elliptic curve?
   else if(!oidComp(oid, length, SECP192R1_OID, sizeof(SECP192R1_OID)))
   {
      curveInfo = SECP192R1_CURVE;
   }
#endif
#if (SECP224K1_SUPPORT == ENABLED)
   //secp224k1 elliptic curve?
   else if(!oidComp(oid, length, SECP224K1_OID, sizeof(SECP224K1_OID)))
   {
      curveInfo = SECP224K1_CURVE;
   }
#endif
#if (SECP224R1_SUPPORT == ENABLED)
   //secp224r1 elliptic curve?
   else if(!oidComp(oid, length, SECP224R1_OID, sizeof(SECP224R1_OID)))
   {
      curveInfo = SECP224R1_CURVE;
   }
#endif
#if (SECP256K1_SUPPORT == ENABLED)
   //secp256k1 elliptic curve?
   else if(!oidComp(oid, length, SECP256K1_OID, sizeof(SECP256K1_OID)))
   {
      curveInfo = SECP256K1_CURVE;
   }
#endif
#if (SECP256R1_SUPPORT == ENABLED)
   //secp256r1 elliptic curve?
   else if(!oidComp(oid, length, SECP256R1_OID, sizeof(SECP256R1_OID)))
   {
      curveInfo = SECP256R1_CURVE;
   }
#endif
#if (SECP384R1_SUPPORT == ENABLED)
   //secp384r1 elliptic curve?
   else if(!oidComp(oid, length, SECP384R1_OID, sizeof(SECP384R1_OID)))
   {
      curveInfo = SECP384R1_CURVE;
   }
#endif
#if (SECP521R1_SUPPORT == ENABLED)
   //secp521r1 elliptic curve?
   else if(!oidComp(oid, length, SECP521R1_OID, sizeof(SECP521R1_OID)))
   {
      curveInfo = SECP521R1_CURVE;
   }
#endif
#if (BRAINPOOLP160R1_SUPPORT == ENABLED)
   //brainpoolP160r1 elliptic curve?
   else if(!oidComp(oid, length, BRAINPOOLP160R1_OID, sizeof(BRAINPOOLP160R1_OID)))
   {
      curveInfo = BRAINPOOLP160R1_CURVE;
   }
#endif
#if (BRAINPOOLP192R1_SUPPORT == ENABLED)
   //brainpoolP192r1 elliptic curve?
   else if(!oidComp(oid, length, BRAINPOOLP192R1_OID, sizeof(BRAINPOOLP192R1_OID)))
   {
      curveInfo = BRAINPOOLP192R1_CURVE;
   }
#endif
#if (BRAINPOOLP224R1_SUPPORT == ENABLED)
   //brainpoolP224r1 elliptic curve?
   else if(!oidComp(oid, length, BRAINPOOLP224R1_OID, sizeof(BRAINPOOLP224R1_OID)))
   {
      curveInfo = BRAINPOOLP224R1_CURVE;
   }
#endif
#if (BRAINPOOLP256R1_SUPPORT == ENABLED)
   //brainpoolP256r1 elliptic curve?
   else if(!oidComp(oid, length, BRAINPOOLP256R1_OID, sizeof(BRAINPOOLP256R1_OID)))
   {
      curveInfo = BRAINPOOLP256R1_CURVE;
   }
#endif
#if (BRAINPOOLP320R1_SUPPORT == ENABLED)
   //brainpoolP320r1 elliptic curve?
   else if(!oidComp(oid, length, BRAINPOOLP320R1_OID, sizeof(BRAINPOOLP320R1_OID)))
   {
      curveInfo = BRAINPOOLP320R1_CURVE;
   }
#endif
#if (BRAINPOOLP384R1_SUPPORT == ENABLED)
   //brainpoolP384r1 elliptic curve?
   else if(!oidComp(oid, length, BRAINPOOLP384R1_OID, sizeof(BRAINPOOLP384R1_OID)))
   {
      curveInfo = BRAINPOOLP384R1_CURVE;
   }
#endif
#if (BRAINPOOLP512R1_SUPPORT == ENABLED)
   //brainpoolP512r1 elliptic curve?
   else if(!oidComp(oid, length, BRAINPOOLP512R1_OID, sizeof(BRAINPOOLP512R1_OID)))
   {
      curveInfo = BRAINPOOLP512R1_CURVE;
   }
#endif
#if (CURVE25519_SUPPORT == ENABLED)
   //Curve25519 elliptic curve?
   else if(!oidComp(oid, length, X25519_OID, sizeof(X25519_OID)))
   {
      curveInfo = X25519_CURVE;
   }
#endif
#if (CURVE448_SUPPORT == ENABLED)
   //Curve448 elliptic curve?
   else if(!oidComp(oid, length, X448_OID, sizeof(X448_OID)))
   {
      curveInfo = X448_CURVE;
   }
#endif
#if (ED25519_SUPPORT == ENABLED)
   //Ed25519 elliptic curve?
   else if(!oidComp(oid, length, ED25519_OID, sizeof(ED25519_OID)))
   {
      curveInfo = ED25519_CURVE;
   }
#endif
#if (ED448_SUPPORT == ENABLED)
   //Ed448 elliptic curve?
   else if(!oidComp(oid, length, ED448_OID, sizeof(ED448_OID)))
   {
      curveInfo = ED448_CURVE;
   }
#endif
   //Unknown identifier?
   else
   {
      curveInfo = NULL;
   }

   //Return the elliptic curve domain parameters, if any
   return curveInfo;
}

#endif
